
import Database from "@tauri-apps/plugin-sql";
import { create } from '@tauri-apps/plugin-fs';

import { homePath, createDirs, uuid, getG01DataBase } from '../../utils';

import { MetaDataDomain, MetaDataObject } from '../types';
import { dataTransform, fileCompressDir, fileUnzip } from "../../services/peer";
import { ConnectorDataSource, queryOne, query, extractorMetaFromDataSource, metaDataSaveObject, metaDataSaveObjectProperty } from "../../services";


export const metaDataGetMetaDomain = async (domainIdentifier: string): Promise<MetaDataDomain | null> => {
    const db = await getG01DataBase();
    //
    let items: Array<any> = await db.select(`select * from _g01_meta_domains where identifier = $1`, [domainIdentifier]);
    if (items && items.length > 0) {
        return items[0];
    }
    return null;
}


export const metaDataGetMetaDatas = async (keywords?: string) => {
    const db = await getG01DataBase();
    if (keywords && keywords != '') {
        //
        let items: Array<any> = await db.select(`select * from _g01_meta_domains where name like $1 order by id desc`, [`%${keywords}%`]);
        console.log(items);
        if (items) {
            return items;
        }
    } else {
        //
        let items: Array<any> = await db.select(`select * from _g01_meta_domains order by id desc`, []);
        console.log(items);
        if (items) {
            return items;
        }
    }
    return [];
}

export const metaDataGetDomains = async (page: number, pageSize: number, keywords?: string): Promise<{ total: number, data: Array<any> }> => {
    const db = await getG01DataBase();

    let offset = (page - 1) * pageSize;

    let conditions = ` `;
    let args = [];
    if (keywords && keywords != '') {
        conditions = ` where name like $1 `;
        args = [`%${keywords}%`];
    }

    let count = (await db.select(`select count(1) cnt from _g01_meta_domains ${conditions}`, args))[0].cnt;
    //
    let items: Array<any> = await db.select(`select * from _g01_meta_domains ${conditions} order by id desc limit ${offset},${pageSize} `, args);
    if (items) {
        return {
            total: count,
            data: items,
        };
    }
    return {
        total: 0,
        data: []
    };
}


export const metaDataGetDomainsByIdentifiers = async (identifiers: Array<string>): Promise<Array<MetaDataDomain>> => {
    const db = await getG01DataBase();

    if (!identifiers || identifiers.length <= 0) return [];

    let conditions = ` where identifier in ( ${identifiers.map(item => `'${item}'`).join(',')} )`;
    let args = [];
    //
    let items: Array<any> = await db.select(`select * from _g01_meta_domains ${conditions} order by id desc`, args);
    console.log(items);
    if (items) {
        return items;
    }
    return [];
}


export const metaDataGetMetaDataObjectByIdentifier = async (objectIdentifier: string): Promise<MetaDataObject | null> => {
    const db = await getG01DataBase();

    //
    let items: Array<any> = await db.select(`select * from _g01_meta_classes where identifier = $1 `, [objectIdentifier]);
    if (items && items.length > 0) {
        return objectDb2Obj(items[0]);
    }
    return null;
}

export const metaDataGetMetaDataObjects = async (domainIdentifier: string, page: number, pageSize: number, keywords?: string): Promise<{ total: number, data: Array<MetaDataObject> }> => {
    const db = await getG01DataBase();

    let offset = (page - 1) * pageSize;

    let conditions = `  where domain_identifier = $1 `;
    let args = [domainIdentifier];
    if (keywords && keywords != '') {
        conditions = ` where domain_identifier = $1 and name like $2 `;
        args = [domainIdentifier, `%${keywords}%`];
    }

    let count = (await db.select(`select count(1) cnt from _g01_meta_classes ${conditions}`, args))[0].cnt;

    //
    let items: Array<any> = await db.select(`select * from _g01_meta_classes ${conditions} order by id desc limit ${offset},${pageSize} `, args);
    if (items) {
        return {
            total: count,
            data: items.map((item, index) => objectDb2Obj(item)),
        };
    }
    return {
        total: 0,
        data: []
    };
}

const objectDb2Obj = (item: any): MetaDataObject => {
    return {
        id: item.id,
        domainIdentifier: item.domain_identifier,
        identifier: item.identifier,
        name: item.name,
        icon: item.icon,
        dataIsType: item.data_is_type === 1,
        description: item.description,
    }
}

export const metaDataSaveDomain = async (obj: MetaDataDomain): Promise<number> => {

    // _g01_meta_class_attributes
    const db = await getG01DataBase();
    //
    if (obj.id > 0) {
        await db.execute(`update _g01_meta_domains set identifier = $1, name = $2, icon = $3, description = $4 where id = $5`,
            [obj.identifier, obj.name, obj.icon, obj.description, obj.id]);
        return 0;
    } else {
        await db.execute(`insert into _g01_meta_domains(identifier,name,icon,description)Values($1,$2,$3,$4)`,
            [obj.identifier, obj.name, obj.icon, obj.description]);

        let res: Array<any> = await db.select('SELECT last_insert_rowid() nid');
        console.log(res);
        if (res && res.length > 0) {
            return res[0].nid;
        }
        return 0;
    }
}

export const metaDataUpdateDomain = async (obj: MetaDataDomain): Promise<number> => {

    // _g01_meta_class_attributes
    const db = await getG01DataBase();
    //
    await db.execute(`update _g01_meta_domains set name = $2, icon = $3, description = $4 where identifier = $1`,
        [obj.identifier, obj.name, obj.icon, obj.description]);
    return 0;
}

export const metaDataImportDomain = async (zip: string): Promise<boolean> => {
    console.log(zip);

    let home = await homePath();

    let exportId = uuid();
    let exportPath = `${home}/temp/${exportId}/`;
    await createDirs(exportPath);

    //解压文件
    let zipRes = await fileUnzip(zip, exportPath);
    //TODO 校验
    //加载sqlite
    //加载数据
    let source: ConnectorDataSource = {
        protocol: 'sqlite',
        url: `sqlite:${exportPath}/domain.sqlite`,
        database_type: 'sqlite',
    };

    let target: ConnectorDataSource = {
        protocol: 'sqlite',
        url: `sqlite:${home}/rrg01.sqlite`,
        database_type: 'sqlite',
    };

    //获取到领域的id
    let domainIdentifier = '';

    let { header, value } = await queryOne(source, 'select identifier from _g01_meta_domains', [], {});
    console.log(value);
    if (value && value.length > 0) {
        domainIdentifier = value[0];
        //查询本地是否存在
        let exist = await query(target, 'select identifier from _g01_meta_domains where identifier =  $1 ', [domainIdentifier], {});
        if (exist && exist.values && exist.values.length > 0) {
            return false;
        }
    } else {
        //
        return false;
    }

    let res = await dataTransform(source, target, [
        {
            "type": "struct",
            "tables": [
                "_g01_meta_domains",
                "_g01_meta_classes",
                "_g01_meta_relations",
                "_g01_meta_traits",
                "_g01_meta_class_attributes",
                "_g01_meta_class_relations",
                "data_meta_data_object_type_mapping_properties",
            ]
        },
        {
            "type": "values",
            "table": "_g01_meta_domains",
            "wheres": ` where identifier = '${domainIdentifier}' `
        },
        {
            "type": "values",
            "table": "_g01_meta_classes",
            "wheres": ` where domain_identifier = '${domainIdentifier}' `
        },
        {
            "type": "values",
            "table": "_g01_meta_relations",
            "wheres": ` where domain_identifier = '${domainIdentifier}' `
        },
        {
            "type": "values",
            "table": "_g01_meta_traits",
            "wheres": ` where domain_identifier = '${domainIdentifier}' `
        },
        {
            "type": "sql",
            "query": `select DISTINCT p.object_identifier, p.identifier, p.name, p.is_key, p.data_type, p.is_number, p.unit, p.description from _g01_meta_class_attributes p, _g01_meta_classes o where o.identifier =  p.object_identifier and o.domain_identifier = '${domainIdentifier}'`,
            "insert": `insert into _g01_meta_class_attributes(object_identifier, identifier, name, is_key, data_type, is_number, unit, description) values($1,$2,$3,$4,$5,$6,$7,$8)`
        },
        {
            "type": "sql",
            "query": `select DISTINCT p.relation_identifier, p.src_identifier, p.target_identifier, p.src_count, p.target_count, p.relation_properties, p.description from _g01_meta_class_relations p, _g01_meta_classes o where (o.identifier =  p.src_identifier  or o.identifier = p.target_identifier)and o.domain_identifier =  '${domainIdentifier}'`,
            "insert": `insert into _g01_meta_class_relations(relation_identifier, src_identifier, target_identifier, src_count, target_count, relation_properties, description) values($1,$2,$3,$4,$5,$6,$7)`
        },
        {
            "type": "sql",
            "query": `select DISTINCT p.object_identifier, p.object_identifier_property, p.object_name_property, p.property_object_identifier, p.property_identifier, p.property_name, p.property_data_type, p.options, p.description from data_meta_data_object_type_mapping_properties p, _g01_meta_classes o where o.identifier =  p.object_identifier and o.domain_identifier =  '${domainIdentifier}'`,
            "insert": `insert into data_meta_data_object_type_mapping_properties p(p.object_identifier, p.object_identifier_property, p.object_name_property, p.property_object_identifier, p.property_identifier, p.property_name, p.property_data_type, p.options, p.description) values($1,$2,$3,$4,$5,$6,$7,$8,$9)`
        }
    ], {
        ignore_errs: true,
        ignore_id: true
    });

    return true;
}


export const metaDataExtractorFromDataSource = async (dataSource: ConnectorDataSource): Promise<any> => {

    let packages = await extractorMetaFromDataSource(dataSource, {});
    console.log(packages);
    let classes = packages?.model_package?.classes;
    if (classes) {
        //创建一个域
        let domainIdentifier = uuid();
        await metaDataSaveDomain({
            identifier: domainIdentifier,
            name: 'test',
        });
        //OBJECT
        for (let i = 0; i < classes.length; i++) {
            try {
                let clazz = classes[i];
                //identity name description comments[]  attributes[]
                //创建一个object
                let objectIdentifier = uuid();
                await metaDataSaveObject({
                    domainIdentifier: domainIdentifier,
                    identifier: objectIdentifier,
                    name: clazz.name,
                    description: clazz.description,
                });
                for (let j = 0; j < clazz.attributes.length; j++) {
                    try {
                        let attr = clazz.attributes[j];
                        // \collection_type\comments\default_value\description\id\identity\is_nullable\name\position\primary_key\scope\type
                        let propertyIdentifier = uuid();
                        await metaDataSaveObjectProperty({
                            objectIdentifier: objectIdentifier,
                            identifier: propertyIdentifier,
                            name: attr.name,
                            dataType: attr.type,
                            collectionType: attr.collection_type,
                            isNullable: !!attr.is_nullable,
                            defaultValue: attr.default_value,
                            position: attr.position,
                            scope: attr.scope,
                            isKey: !!attr.primary_key,
                            comment: attr.comments.join(','),
                            options: JSON.stringify(attr.options),
                            description: attr.description,
                        });
                    } catch (error) {
                        console.error(error);
                    }
                }
            } catch (error) {
                console.error(error);
            }
        }
        //
    }
}

export default {};